package com.xz.diagnosisOrder.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xz.common.annotation.DataScope;
import com.xz.common.core.domain.entity.SysDept;
import com.xz.common.core.domain.entity.SysUser;
import com.xz.common.core.domain.model.LoginUser;
import com.xz.common.exception.ServiceException;
import com.xz.common.utils.DateUtils;
import com.xz.common.utils.RedisCode;
import com.xz.common.utils.SecurityUtils;
import com.xz.common.utils.StringUtils;
import com.xz.diagnosis.domain.DiagnosisCause;
import com.xz.diagnosis.domain.DiagnosisRegistrationFee;
import com.xz.diagnosis.domain.DiagnosisTime;
import com.xz.diagnosis.mapper.DiagnosisRegistrationFeeMapper;
import com.xz.diagnosis.service.IDiagnosisCauseService;
import com.xz.diagnosis.service.IDiagnosisTimeService;
import com.xz.diagnosisOrder.domain.DiagnosisOrder;
import com.xz.diagnosisOrder.dto.DiagnosisOrderSaveDto;
import com.xz.diagnosisOrder.enums.ArrivalStatusEnum;
import com.xz.diagnosisOrder.enums.DiagnosisOrderTypeEnum;
import com.xz.diagnosisOrder.enums.PaymentStatusEnum;
import com.xz.diagnosisOrder.mapper.DiagnosisOrderMapper;
import com.xz.diagnosisOrder.service.IDiagnosisExpenseService;
import com.xz.diagnosisOrder.service.IDiagnosisOrderLogService;
import com.xz.diagnosisOrder.service.IDiagnosisOrderService;
import com.xz.diagnosisOrder.service.IDiagnosisRefundOrderService;
import com.xz.diagnosisOrder.vo.DiagnosisOrderDetailVo;
import com.xz.diagnosisOrder.vo.DiagnosisOrderListVo;
import com.xz.diagnosisOrder.vo.OrderServiceDeskListVo;
import com.xz.member.domain.MemberInfo;
import com.xz.member.domain.MemberLevel;
import com.xz.member.domain.MemberPatient;
import com.xz.member.service.IMemberInfoService;
import com.xz.member.service.IMemberLevelService;
import com.xz.member.service.IMemberPatientService;
import com.xz.member.service.IWalletRecordService;
import com.xz.patient.domain.PatientInfo;
import com.xz.patient.mapper.PatientInfoMapper;
import com.xz.system.service.ISysDeptService;
import com.xz.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 诊疗（预约/挂号）单Service业务层处理
 *
 * @author xz
 * @date 2024-03-17
 */
@Service
public class DiagnosisOrderServiceImpl extends ServiceImpl<DiagnosisOrderMapper, DiagnosisOrder> implements IDiagnosisOrderService {

  @Autowired
  private DiagnosisOrderMapper diagnosisOrderMapper;
  @Autowired
  private PatientInfoMapper patientInfoMapper;
  @Autowired
  private DiagnosisRegistrationFeeMapper diagnosisRegistrationFeeMapper;
  @Autowired
  private IDiagnosisTimeService diagnosisTimeService;
  @Autowired
  private IDiagnosisExpenseService diagnosisExpenseService;
  @Autowired
  private IDiagnosisRefundOrderService diagnosisRefundOrderService;
  @Autowired
  private IDiagnosisCauseService diagnosisCauseService;
  @Autowired
  private IMemberLevelService memberLevelService;
  @Autowired
  private ISysUserService sysUserService;
  @Autowired
  private ISysDeptService sysDeptService;
  @Autowired
  private IDiagnosisOrderLogService diagnosisOrderLogService;
  @Autowired
  private IMemberPatientService memberPatientService;
  @Autowired
  private IMemberInfoService memberInfoService;
  @Autowired
  private IWalletRecordService walletRecordService;
  /**
   * 查询诊疗（预约/挂号）单
   *
   * @param id 诊疗（预约/挂号）单主键
   * @return 诊疗（预约/挂号）单
   */
  @Override
  public DiagnosisOrder selectDiagnosisOrderById(Long id) {
    return diagnosisOrderMapper.selectDiagnosisOrderById(id);
  }

  /**
   * 查询诊疗（预约/挂号）单
   *
   * @param ids 诊疗（预约/挂号）单主键
   * @return 诊疗（预约/挂号）单
   */
  @Override
  public List<DiagnosisOrder> selectDiagnosisOrderDetailVoByIds(Long[] ids) {
    List<DiagnosisOrder> orderList = diagnosisOrderMapper.selectBatchIds(Arrays.asList(ids));
    return orderList;
  }

  /**
   * 查询诊疗（预约/挂号）单
   *
   * @param id 诊疗（预约/挂号）单主键
   * @return 诊疗（预约/挂号）单
   */
  @Override
  public DiagnosisOrderDetailVo selectDiagnosisOrderDetailVoById(Long id) {

    DiagnosisOrder order = diagnosisOrderMapper.selectDiagnosisOrderById(id);
    DiagnosisOrderDetailVo vo = getDiagnosisOrderDetailVo(order);
    return vo;
  }

  private DiagnosisOrderDetailVo getDiagnosisOrderDetailVo(DiagnosisOrder order) {
    DiagnosisOrderDetailVo vo = new DiagnosisOrderDetailVo();
    if (null == order) {
      return vo;
    }
    BeanUtils.copyProperties(order, vo);
    // 患者信息
    PatientInfo patientInfo = patientInfoMapper.selectById(order.getPatientId());
    if (null != patientInfo) {
      vo.setPatientName(patientInfo.getPatientName());
      vo.setPhoneNumber(patientInfo.getPhoneNumber());
      vo.setFileNo(patientInfo.getFileNo());
      vo.setReferenceType(patientInfo.getReferenceType());
      vo.setSex(patientInfo.getSex());
      vo.setBirthday(patientInfo.getBirthday());
      vo.setDocumentType(patientInfo.getDocumentType());
      vo.setDocumentNo(patientInfo.getDocumentNo());
      vo.setAddress(patientInfo.getAddress());
      Date birthday = patientInfo.getBirthday();
      if (null != birthday) {
        Calendar cal = Calendar.getInstance();
        int currentYear = cal.get(Calendar.YEAR);
        cal.setTime(birthday);
        int birthdayYear = cal.get(Calendar.YEAR);
        vo.setAge(currentYear - birthdayYear);
      }
    }
    //制单人
    if(null != order.getCreateBy()){
      SysUser user = sysUserService.selectUserById(order.getCreateBy());
      if(null != user){
        vo.setCreateByName(user.getUserName());
      }
    }
    //门店
    if(null != order.getDeptId()){
      SysDept dept = sysDeptService.selectDeptById(order.getDeptId());
      if(null != dept){
        vo.setDeptName(dept.getDeptName());
      }
    }

    if(StringUtils.isEmpty(vo.getMemberCardNo())){
      MemberPatient memberPatient = memberPatientService.selectByPatientId(patientInfo.getId());
      if(null != memberPatient){
        vo.setMemberCardNo(memberPatient.getMemberCardNo());
      }
    }

    //默认0
    vo.setWalletBalance(BigDecimal.ZERO);
    vo.setIntegralBalance(BigDecimal.ZERO);
    vo.setAccumulatedRecharge(BigDecimal.ZERO);

    //根据会员卡号反查会员等级权益信息，找出折扣，并且赋值
    String memberCardNo = vo.getMemberCardNo();
    if (!StringUtils.isEmpty(memberCardNo)) {
      MemberLevel level = memberLevelService.getByMemberCardNo(memberCardNo);
      if (null != level && null != level.getDiscount()) {
        vo.setMemberLevelDiscount(level.getDiscount().divide(new BigDecimal(10)));
      }
      MemberInfo member = memberInfoService.selectByMemberCarNo(memberCardNo);
      if(null != member){
        vo.setWalletBalance(member.getWalletBalance() == null ? BigDecimal.ZERO : member.getWalletBalance());
        vo.setIntegralBalance(member.getIntegralBalance() == null ? BigDecimal.ZERO : member.getIntegralBalance());
        vo.setAccumulatedRecharge(member.getAccumulatedRecharge() == null ? BigDecimal.ZERO : member.getAccumulatedRecharge());
      }
    }
    return vo;
  }


  /**
   * 查询诊疗（预约/挂号）单列表
   *
   * @param diagnosisOrder 诊疗（预约/挂号）单
   * @return 诊疗（预约/挂号）单
   */
  @Override
  public List<DiagnosisOrder> selectDiagnosisOrderList(DiagnosisOrder diagnosisOrder) {
    return diagnosisOrderMapper.selectDiagnosisOrderList(diagnosisOrder);
  }

  /**
   * 查询就诊单列表
   *
   * @param diagnosisOrder 就诊单
   * @return 就诊单
   */
  @Override
  @DataScope(deptAlias = "d", userAlias = "u")
  public List<DiagnosisOrderListVo> selectDiagnosisOrderVoList(DiagnosisOrder diagnosisOrder) {
    return diagnosisOrderMapper.selectDiagnosisOrderVoList(diagnosisOrder);
  }

  /**
   * 查询诊疗（预约/挂号）单列表
   *
   * @param diagnosisOrder 诊疗（预约/挂号）单
   * @return 诊疗（预约/挂号）单
   */
  @Override
  @DataScope(deptAlias = "d", userAlias = "u")
  public List<OrderServiceDeskListVo> selectOrderServiceDeskList(DiagnosisOrder diagnosisOrder) {
    return diagnosisOrderMapper.selectOrderServiceDeskList(diagnosisOrder);
  }

  /**
   * 新增诊疗（预约/挂号）单
   *
   * @param dto 诊疗（预约/挂号）单
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int insertDiagnosisOrder(DiagnosisOrderSaveDto dto) {
    DiagnosisOrder entity = new DiagnosisOrder();
    BeanUtils.copyProperties(dto, entity);
    //替换字段
    replaceFields(entity);
    // 新增时，如果状态传入的是1.未到店，说明是预约单，反之是挂号单
    if (ArrivalStatusEnum.NOT_ARRIVED.eq(entity.getArrivalStatus())) {
      entity.setOrderType(DiagnosisOrderTypeEnum.APPOINTMENT_FORM.getType());
    } else {
      entity.setOrderType(DiagnosisOrderTypeEnum.REGISTRATION_FORM.getType());
    }
    //单号
    entity.setOrderNo(RedisCode.getCode("GH"));
    //填充创建人信息
    LoginUser user = SecurityUtils.getLoginUser();
    entity.setCreateBy(user.getUserId());
    entity.setCreateTime(DateUtils.getNowDate());
    entity.setTenantId(user.getTenantId());
    entity.setDeptId(user.getDeptId());
    int res = diagnosisOrderMapper.insertDiagnosisOrder(entity);
    if (0 < res) {
      // 钱包支付的处理
      diagnosisExpenseService.deductionOfAccountBalance(entity);
    }
    return res;
  }


  /**
   * 修改诊疗（预约/挂号）单
   *
   * @param dto 诊疗（预约/挂号）单
   * @return 结果
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int updateDiagnosisOrder(DiagnosisOrderSaveDto dto) {
    DiagnosisOrder entity = baseMapper.selectById(dto.getId());
    BeanUtils.copyProperties(dto, entity);
    //替换字段
    replaceFields(entity);
    //填充更新人信息
    LoginUser user = SecurityUtils.getLoginUser();
    entity.setUpdateBy(user.getUserId());
    entity.setUpdateTime(DateUtils.getNowDate());
    int res = diagnosisOrderMapper.updateDiagnosisOrder(entity);
    if (0 < res) {
      // 钱包支付的处理
      diagnosisExpenseService.deductionOfAccountBalance(entity);
    }
    return res;
  }

  /**
   * 替换字段
   *
   * @param entity
   */
  private void replaceFields(DiagnosisOrder entity) {

    PatientInfo patientInfo = patientInfoMapper.selectById(entity.getPatientId());
    if (null == patientInfo) {
      throw new ServiceException("该客户不存在或已被删除");
    }
    //填充挂号费设置
    if(null != entity.getRegistrationFeeId()){
      DiagnosisRegistrationFee registrationFee = diagnosisRegistrationFeeMapper.selectById(entity.getRegistrationFeeId());
      if (null == registrationFee) {
        throw new ServiceException("该挂号费设置已失效");
      }
      entity.setDoctorName(registrationFee.getDoctorName());
      entity.setRegistrationFeeType(registrationFee.getRegistrationFeeType());
      entity.setRegistrationFee(registrationFee.getRegistrationFee());
    }else{
      entity.setRegistrationFee(BigDecimal.ZERO);
    }

    // 重新计算金额
    // 优惠金额--缺省情况下等于0
    entity.setReduceAmount(null == entity.getReduceAmount() ? BigDecimal.ZERO : entity.getReduceAmount());
    entity.setPreferentialAmount(entity.getReduceAmount());
    // (应)收款金额 = 挂号费 - 优惠金额
    BigDecimal collectionAmount = entity.getRegistrationFee().subtract(entity.getReduceAmount());
    if (collectionAmount.compareTo(BigDecimal.ZERO) == -1) {
      throw new ServiceException("收款金额不能为负数");
    }
    entity.setCollectionAmount(collectionAmount);
    // 到店的钱包支付金额 > 缺省情况下等于0
    entity.setWalletPay(null == entity.getWalletPay() ? BigDecimal.ZERO : entity.getWalletPay());
    // 待收金额 = (应)收款金额 - 钱包支付金额
    BigDecimal pendingAmount = collectionAmount.subtract(entity.getWalletPay());
    if (pendingAmount.compareTo(BigDecimal.ZERO) == -1) {
      throw new ServiceException("待收金额不能为负数");
    }
    entity.setPendingAmount(pendingAmount);

    // 未到店的状态下相关字段校验和值填充。
    if (ArrivalStatusEnum.NOT_ARRIVED.eq(entity.getArrivalStatus())) {
      // 到店的同时是支付挂号费
      entity.setPaymentStatus(PaymentStatusEnum.UNPAID.getStatus());
    } else {
      // 到店的状态下相关字段校验和值填充。
      //到店的情况下，如果钱包金额大于0，则必须要前端传入会员的卡号
      if (ArrivalStatusEnum.ARRIVED.eq(entity.getArrivalStatus())
        && null != entity.getWalletPay()
        && entity.getWalletPay().compareTo(BigDecimal.ZERO) == 1
        && StringUtils.isEmpty(entity.getMemberCardNo())) {
        throw new ServiceException("无法使用钱包支付，该会员的卡号不存在");
      }
      //到店的情况下，如果金额大于0，则必须要前端传入支付方式
      if (ArrivalStatusEnum.ARRIVED.eq(entity.getArrivalStatus())
        && null == entity.getPendingAmount()
        && entity.getPendingAmount().compareTo(BigDecimal.ZERO) == 1
        && null == entity.getPaymentType()) {
        throw new ServiceException("请选择支付方式");
      }
      // 到店要更新支付时间，支付状态
      entity.setPaymentTime(new Date());
      entity.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
    }

    //填充就诊时间设置
    DiagnosisTime diagnosisTime = diagnosisTimeService.selectDiagnosisTimeById(entity.getDiagnosisTimeId());
    if (null == diagnosisTime) {
      throw new ServiceException("该就诊时间段设置已失效");
    }
    entity.setDiagnosisTime(diagnosisTime.getTimePeriod());
    entity.setDiagnosisTimeGroup(diagnosisTime.getGroupName());

    //填充就诊事项
    DiagnosisCause diagnosisCause = diagnosisCauseService.selectDiagnosisCauseById(entity.getDiagnosisItemId());
    if (null == diagnosisCause) {
      throw new ServiceException("该就诊事项设置已失效");
    }
    entity.setDiagnosisItem(diagnosisCause.getCause());
  }

  /**
   * 取消预约
   *
   * @param id
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int cancelById(Long id) {

    DiagnosisOrder order = baseMapper.selectById(id);
    // 查出数据后开始校验状态是否支持取消,只有未到店的数据，才能取消预约
    if (null != order
      //&& ArrivalStatusEnum.NOT_ARRIVED.eq(order.getArrivalStatus())
    ) {
      LambdaUpdateWrapper<DiagnosisOrder> wrapper = Wrappers.lambdaUpdate(DiagnosisOrder.class);
      wrapper.set(DiagnosisOrder::getArrivalStatus, ArrivalStatusEnum.CANCEL.getStatus());
      wrapper.set(DiagnosisOrder::getUpdateBy, SecurityUtils.getLoginUser().getUserId());
      wrapper.set(DiagnosisOrder::getUpdateTime, DateUtils.getNowDate());
      wrapper.eq(DiagnosisOrder::getId, id);
      update(wrapper);
    }
    return 1;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean refundFeeById(Long id) {

    DiagnosisOrder order = baseMapper.selectById(id);
    // 查出数据后开始校验状态是否支持取消,只有到店,并且付款的数据，才能退单
    if (null == order || !PaymentStatusEnum.PAID.eq(order.getPaymentStatus())) {
      throw new ServiceException("操作失败，只有已付款状态的单据才能执行退号操作");
    }
    // 更新挂号单数据
    LambdaUpdateWrapper<DiagnosisOrder> wrapper = Wrappers.lambdaUpdate(DiagnosisOrder.class);
    wrapper.set(DiagnosisOrder::getPaymentStatus, PaymentStatusEnum.PENDING_REFUND.getStatus());
    wrapper.set(DiagnosisOrder::getUpdateBy, SecurityUtils.getLoginUser().getUserId());
    wrapper.set(DiagnosisOrder::getUpdateTime, DateUtils.getNowDate());
    wrapper.eq(DiagnosisOrder::getId, id);
    boolean flag = update(wrapper);
    if (flag) {
      //开始创建退费申请单记录
      diagnosisRefundOrderService.insertByOrder(order);
    }
    return flag;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean setPaymentStatusByBatchId(List<Long> id, Integer status) {

    // 更新挂号单数据
    LambdaUpdateWrapper<DiagnosisOrder> wrapper = Wrappers.lambdaUpdate(DiagnosisOrder.class);
    wrapper.set(DiagnosisOrder::getPaymentStatus, status);
    wrapper.set(DiagnosisOrder::getUpdateBy, SecurityUtils.getLoginUser().getUserId());
    wrapper.set(DiagnosisOrder::getUpdateTime, DateUtils.getNowDate());
    wrapper.in(DiagnosisOrder::getId, id);
    // 只有已退款（退款成功）才会会生成对应的日志报表，钱包记录
    if (status.equals(3)) {
      List<DiagnosisOrder> orders = this.baseMapper.selectBatchIds(id);
      orders.forEach(order->{
        // 诊疗模块的报表日志
        diagnosisOrderLogService.insertByOrder(order, 2, 1);
        // 钱包相关操作
        BigDecimal walletPay = order.getWalletPay();
        if(null != walletPay && walletPay.compareTo(BigDecimal.ZERO) == 1){
          // 新增钱包流水记录（7:挂号单退款 , 1:加钱）
          walletRecordService.addBizRecord(order.getMemberCardNo(), 7, 1, order.getOrderNo(), order.getWalletPay(), order.getDeptId());
          // 返还会员的钱包余额
          diagnosisExpenseService.refundAccountBalance(walletPay, order.getMemberCardNo());
        }
      });
    }
    return update(wrapper);
  }
}
